<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- JavaScript是单线程的，因为只有一个调用堆栈处理我们的函数。 
    当浏览器加载某些JS代码时，JS引擎会逐行读取并执行以下步骤： 
    将变量和函数的声明放入全局内存(堆)中, 将函数的调用放入调用堆栈
    创建全局执行上下文，在其中执行全局函数, 创建多个本地执行上下文(如果有内部变量或嵌套函数) 
    事件循环 :。它是一个在 JavaScript
    引擎等待任务，执行任务和进入休眠状态等待更多任务这几个状态之间转换的无限循环。
    引擎的一般算法：

    当有任务时：
    从最先进入的任务开始执行。
    休眠直到出现任务，然后转到第 1 步。
    当我们浏览一个网页时就是上述这种形式。JavaScript 引擎大多数时候不执行任何操作，它仅在脚本/处理程序/事件激活时执行。
    任务示例：
    当外部脚本 <script src="..."> 加载完成时，任务就是执行它。
    当用户移动鼠标时，任务就是派生出 mousemove 事件和执行处理程序。
    当安排的（scheduled）setTimeout 时间到达时，任务就是执行其回调。
    ……诸如此类。
    设置任务 —— 引擎处理它们 —— 然后等待更多任务（即休眠，几乎不消耗 CPU 资源）。
    一个任务到来时，引擎可能正处于繁忙状态，那么这个任务就会被排入队列。
    多个任务组成了一个队列，即所谓的“宏任务队列”（v8 术语）：
    每个异步函数在被放入调用堆栈之前必须通过回调队列，但这个工作是谁做的呢，那就是事件循环(Event Loop)。
    事件循环只有一个任务:它检查调用堆栈是否为空。如果回调队列中(Callback Queue)有某个函数，并且调用堆栈是空闲的，
    那么就将其放入调用堆栈中。 -->
    <script>
      var num = 2
      function pow(num) {
        return num * num
      }
      pow(num)
      setTimeout(callback, 10000)
      function callback() {
        console.log('hello timer!')
      }

      /* setTimeout在浏览器上下文中运行。10秒后，计时器被触发，回调函数准备运行。但首先它必须通过回调队列(Callback Queue)。回调队列是一个队列数据结构，回调队列是一个有序的函数队列。
      每个异步函数在被放入调用堆栈之前必须通过回调队列，但这个工作是谁做的呢，那就是事件循环(Event Loop)。
      事件循环只有一个任务:它检查调用堆栈是否为空。如果回调队列中(Callback Queue)有某个函数，并且调用堆栈是空闲的，那么就将其放入调用堆栈中。 */
      /* 微任务仅来自于我们的代码。它们通常是由 promise 创建的：对 .then/catch/finally 处理程序的执行会成为微任务。微任务也被用于 await 的“幕后”，因为它是 promise 处理的另一种形式。
还有一个特殊的函数 queueMicrotask(func)，它对 func 进行排队，以在微任务队列中执行。
每个宏任务之后，引擎会立即执行微任务队列中的所有任务，然后再执行其他的宏任务，或渲染，或进行其他任何操作。 */

      // 微任务会在执行任何其他事件处理，或渲染，或执行任何其他宏任务之前完成。

      // 这很重要，因为它确保了微任务之间的应用程序环境基本相同（没有鼠标坐标更改，没有新的网络数据等）。

      // 如果我们想要异步执行（在当前代码之后）一个函数，但是要在更改被渲染或新事件被处理之前执行，那么我们可以使用 queueMicrotask 来对其进行安排（schedule）。

      /* 从 宏任务 队列（例如 “script”）中出队（dequeue）并执行最早的任务。
执行所有 微任务：
当微任务队列非空时：
出队（dequeue）并执行最早的微任务。
执行渲染，如果有。
如果宏任务队列为空，则休眠直到出现宏任务。
转到步骤 1。
安排（schedule）一个新的 宏任务：

使用零延迟的 setTimeout(f)。
它可被用于将繁重的计算任务拆分成多个部分，以使浏览器能够对用户事件作出反应，并在任务的各部分之间显示任务进度。

此外，也被用于在事件处理程序中，将一个行为（action）安排（schedule）在事件被完全处理（冒泡完成）后。

安排一个新的 微任务：

使用 queueMicrotask(f)。
promise 处理程序也会通过微任务队列。
在微任务之间没有 UI 或网络事件的处理：它们一个立即接一个地执行。

所以，我们可以使用 queueMicrotask 来在保持环境状态一致的情况下，异步地执行一个函数。 */

      // 对吗 ？   脚本 => 微任务 => 渲染 => 事件 =》 微任务 =》 渲染 =》 setTimeout

      // =============================================>
      // 使用xhr 发起post请求
      // - 创建 xhr 对象
      // - 调用 xhr.open() 函数
      // - 设置 Content-Type 属性（固定写法）
      // - 调用 xhr.send() 函数，同时指定要发送的数据
      // - 监听 xhr.onreadystatechange 事件

      // 1. 创建 xhr 对象
      var xhr = new XMLHttpRequest()
      // 2. 调用 open 函数
      xhr.open('POST', 'http://www.liulongbin.top:3006/api/addbook')
      // 3. 设置 Content-Type 属性（固定写法） 这行代码必须在 open之后  send 之前
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
      // 4. 调用 send 函数 同时将数据以字符串拼接 提交给服务器
      xhr.send('bookname=水浒传&author=施耐庵&publisher=上海图书出版社')
      // 5. 监听事件
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.responseText)
        }
      }
    </script>
  </body>
</html>
